/**

   llist.c
   =======

   Datacenter linked lists

**/


/**

   Includes
   --------

   - stdlib.h : malloc, free
   - dc.h     : datacenters
   - llist.h  : self header

**/


#include <stdlib.h>
#include "dc.h"
#include "llist.h"




/**

   Function: struct llist* llist_create(int (*compare)(struct dc*, struct dc*))
   ----------------------------------------------------------------------------

   Create a llist.

**/


struct llist* llist_create(int (*compare)(struct dc*, struct dc*))
{
  struct llist* ll;

  ll = (struct llist*)malloc(sizeof(struct llist));
  if (ll == NULL)
    {
      return NULL;
    }

  ll->head = NULL;
  ll->compare = compare;

  return ll;

}


/**
   
   Function: int llist_delete(struct llist* ll)
   --------------------------------------------

   Delete an empty llist

**/


int llist_delete(struct llist* ll)
{
  /* Sanity checks */
  if (ll == NULL)
    {
      return EXIT_FAILURE;
    }

  if (ll->head)
    {
      return EXIT_FAILURE;
    }

  free(ll);

  return EXIT_SUCCESS;

}


/**

   Function: int llist_insert(struct llist* ll,struct dc* dc)
   ----------------------------------------------------------

   Inser `dc` in sorted `ll`

**/


int llist_insert(struct llist* ll,struct dc* dc)
{
  struct dc* cursor;

  /* Sanity checks */
  if ( (ll==NULL) || (dc==NULL) )
    {
      return EXIT_FAILURE;
    }

  /* Empty list case  */
  if (ll->head == NULL)
    {
      ll->head = dc;
      dc->next = dc;
      dc->prev = dc;
      
      return EXIT_SUCCESS;
    }

  /* Look for right place to insert into */
  cursor = ll->head;
  do
    {
      if (ll->compare(dc,cursor) > 0)
	{
	  cursor = cursor->next;
	}
      else
	{
	  break;
	}
    }while( (cursor != ll->head) );

  /* Insert */
  dc->next=cursor;
  (cursor->prev)->next = dc;
  dc->prev = cursor->prev;
  cursor->prev = dc;
  
  /* New head case */
  if ( (cursor == ll->head)&&(ll->compare(dc,cursor) < 0) )
    {
      ll->head = dc;
    }

  return EXIT_SUCCESS;

}


/**

   Function: int llist_remove(struct llist* ll, struct dc* dc)
   -----------------------------------------------------------

   Remove `dc` from `ll`

**/


int llist_remove(struct llist* ll, struct dc* dc)
{
  
  (dc->prev)->next = dc->next;
  (dc->next)->prev = dc->prev;
  
  /* Head case */
  if (ll->head == dc)
    {
      if (dc->next == dc)
	{
	  /* Singleton case */
	  ll->head = NULL;
	}
      else
	{
	  ll->head = dc->next;
	}
    }

  return EXIT_SUCCESS;

}
